package com.niiwoo.civet.account.service.local.openAccount;

import com.niiwoo.civet.account.constant.AccountRegisterErrorCode;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.AccountPerson;
import com.niiwoo.civet.account.dao.entity.BankCard;
import com.niiwoo.civet.account.dao.entity.OpenAccountOrder;
import com.niiwoo.civet.account.dao.entity.OpenAccountRecord;
import com.niiwoo.civet.account.dto.common.LanMaoGatewayRequestDTO;
import com.niiwoo.civet.account.dto.request.CreateRegisterOrderRequestDTO;
import com.niiwoo.civet.account.dto.request.UpdateRegisterOrderRequestDTO;
import com.niiwoo.civet.account.dto.response.UpdateRegisterOrderResponseDTO;
import com.niiwoo.civet.account.enums.AccountActiveEnum;
import com.niiwoo.civet.account.enums.AccountTypeEnum;
import com.niiwoo.civet.account.enums.OpenAccountOrderStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountRecordStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountWayEnum;
import com.niiwoo.civet.account.service.local.AccountPersonService;
import com.niiwoo.civet.account.service.local.BankCardService;
import com.niiwoo.civet.account.service.local.OpenAccountOrderService;
import com.niiwoo.civet.account.service.local.OpenAccountRecordService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.lanmao.component.LanMaoGatewayService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

//@Component
public class PersonalOpenAccountService extends AbstractOpenAccountService<UpdateRegisterOrderRequestDTO, UpdateRegisterOrderResponseDTO> {

    private static final List<UserRoleEnum> SUPPORT_ROLE_LIST = Arrays.asList(UserRoleEnum.INVESTOR, UserRoleEnum.BORROWERS);

    private static final List<OpenAccountWayEnum> SUPPORT_WAY_LIST = Arrays.asList(OpenAccountWayEnum.PERSON_BIND_BANK_CARD_REGISTER, OpenAccountWayEnum.R360_PERSON_BIND_BANK_CARD_REGISTER);

    @Autowired
    OpenAccountTemplate openAccountTemplate;

    @Autowired
    OpenAccountOrderService openAccountOrderService;

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    OpenAccountRecordService openAccountRecordService;

    @Autowired
    BankCardService bankCardService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Autowired
    AccountPersonService accountPersonService;

    @Autowired
    LanMaoSequence lanMaoSequence;

    @Autowired
    LanMaoGatewayService lanMaoGatewayService;

    @Override
    protected LanMaoGatewayRequestDTO internalCreateOrder(CreateRegisterOrderRequestDTO requestDTO) {
        // 查询开户记录
        List<OpenAccountRecord> recordList = Optional.ofNullable(openAccountRecordService.getByUserId(requestDTO.getUserId())).orElse(Collections.EMPTY_LIST);
        // 当前角色开户记录
        Optional<OpenAccountRecord> currentRoleRecordOpt = recordList.stream()
                .filter(r -> Objects.equals(r.getAccountRole(), Integer.valueOf(requestDTO.getAccountRole().getValue()).byteValue()))
                .findFirst();
        currentRoleRecordOpt.ifPresent(r -> {
            switch (OpenAccountRecordStatusEnum.of(r.getStatus())) {
                case AUDITING:
                    throw new BizException(AccountRegisterErrorCode.ACCOUNT_AUDITING);
                case SUCCESS:
                    throw new BizException(AccountRegisterErrorCode.HAS_REGISTERED_ACCOUNT);
            }
        });
        // 其他角色开户记录
        recordList.stream()
                .filter(r -> !Objects.equals(r.getAccountRole(), Integer.valueOf(requestDTO.getAccountRole().getValue()).byteValue()))
                .findFirst()
                .ifPresent(r -> {
                    switch (OpenAccountRecordStatusEnum.of(r.getStatus())) {
                        case PROCESSING:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_PROCESSING_ACCOUNT);
                        case AUDITING:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_AUDITING_ACCOUNT);
                        case AUDIT_RETURN:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_AUDIT_RETURN_ACCOUNT);
                        case SUCCESS:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_REGISERED_ACCOUNT);
                    }
                });
        // 如果存在待激活记录
        Optional<AccountBase> unactivatedOpt = Optional.ofNullable(openAccountRecordService.getAccountBaseList(requestDTO.getUserId()))
                .filter(list -> !list.isEmpty())
                .flatMap(list -> list.stream().filter(a -> a.getImportUserActiva().equals(AccountActiveEnum.UNACTIVATED.getValue())).findFirst());
        unactivatedOpt.map(b -> accountPersonService.get(b.getId()))
                .ifPresent(p -> {
                    // 比较传入的姓名
                    if (!requestDTO.getName().equals(p.getRealName())) {
                        throw new BizException(AccountRegisterErrorCode.NOT_MATCH_NAME_AND_ID_CARD);
                    }
                    // 比较传入的身份证号码
                    if (!requestDTO.getIdCardNo().equals(privacyMasks.decryptPrivacy(p.getIdCard()))) {
                        throw new BizException(AccountRegisterErrorCode.NOT_MATCH_NAME_AND_ID_CARD);
                    }
                });
        // 获取更新或初始化开户记录
        OpenAccountRecord record = AccountEntityBuilder.buildRefreshOpenAccountRecord(currentRoleRecordOpt, () -> snowflakeIdWorker.nextId(), () -> String.valueOf(snowflakeIdWorker.nextId()), "", requestDTO);
        // 创建开户订单
        OpenAccountOrder order = AccountEntityBuilder.buildInitOpenAccountOrder(
                snowflakeIdWorker.nextId(),
                lanMaoSequence.getRequestNo(),
                currentRoleRecordOpt.orElse(record),
                requestDTO,
                text -> privacyMasks.encryptPrivacy(text),
                openAccountTemplate.getAuthTextByRole(requestDTO.getAccountRole())
        );
        // 更新开户记录和订单
        if (!openAccountRecordService.saveRecordAndAccountOrder(currentRoleRecordOpt.isPresent(), record, () -> openAccountOrderService.saveOrder(order))) {
            throw new BizException(AccountRegisterErrorCode.CREATE_ACCOUNT_REGISTER_ORDER_FAIL);
        }
        // 创建网关请求参数并返回
        return AccountLanMaoGatewayRequestBuilder.newPersonalBindBankCardRegisterRequest(req -> lanMaoGatewayService.personalBindBankCardRegister(req), order, requestDTO, unactivatedOpt.isPresent());
    }

    @Override
    public UpdateRegisterOrderResponseDTO updateOrder(UpdateRegisterOrderRequestDTO requestDTO) {
        assertSupportRole(requestDTO.getRole());
        return doUpdateOrder(
                () -> openAccountOrderService.getByRequestNo(requestDTO.getRequestNo()),
                order -> OpenAccountOrderStatusEnum.except(order.getStatus(), OpenAccountOrderStatusEnum.SUCCESS),
                order -> {
                    UpdateRegisterOrderResponseDTO responseDTO = new UpdateRegisterOrderResponseDTO();
                    responseDTO.setOrderId(order.getId());
                    responseDTO.setRequestNo(order.getRequestNo());
                    responseDTO.setOrderStatus(OpenAccountOrderStatusEnum.SUCCESS);
                    return responseDTO;
                },
                order -> openAccountRecordService.getByUserIdAndRole(order.getUserId(), UserRoleEnum.enumOf(order.getUserRole())),
                (order, record) -> {
                    UpdateRegisterOrderResponseDTO responseDTO = new UpdateRegisterOrderResponseDTO();
                    responseDTO.setOrderId(order.getId());
                    responseDTO.setRequestNo(order.getRequestNo());
                    OpenAccountOrderStatusEnum orderStatus;
                    switch (requestDTO.getStatus()) {
                        case SUCCESS: {
                            orderStatus = updateSuccessOrder(record, order, requestDTO);
                        }
                        break;
                        case FAILURE: {
                            orderStatus = updateFailOrder(record, order, requestDTO);
                        }
                        break;
                        default: {
                            orderStatus = OpenAccountOrderStatusEnum.of(order.getStatus());
                        }
                    }
                    responseDTO.setOrderStatus(orderStatus);
                    return responseDTO;
                }
        );
    }

    @Override
    protected List<UserRoleEnum> getSupportRole() {
        return SUPPORT_ROLE_LIST;
    }

    @Override
    protected List<OpenAccountWayEnum> getSupportWay() {
        return SUPPORT_WAY_LIST;
    }

    private OpenAccountOrderStatusEnum updateSuccessOrder(OpenAccountRecord record, OpenAccountOrder order, UpdateRegisterOrderRequestDTO requestDTO) {
        Set<String> authSet = Optional.ofNullable(order.getAuthList())
                .map(s -> {
                    Set<String> set = new HashSet<>(Arrays.asList(s.split(",")));
                    return set;
                })
                .orElse(Collections.EMPTY_SET);
        // 账户基础
        AccountBase accountBase = AccountEntityBuilder.buildInitAccountBase(snowflakeIdWorker.nextId(), record, AccountTypeEnum.PERSONAL, authSet);
        // 账户个人
        AccountPerson person = AccountEntityBuilder.buildInitAccountPerson(record, accountBase, requestDTO.getName(), privacyMasks.encryptPrivacy(requestDTO.getCertNo()), requestDTO.getCertType());
        BankCard preBankCard = bankCardService.getSimpleUserBankCard(record.getUserId());
        // 银行卡更新函数
        Supplier<Boolean> s2 = openAccountTemplate.getUpdateBankFunction(preBankCard, accountBase.getUserId(), accountBase.getId(), AccountTypeEnum.PERSONAL, requestDTO.getName(), requestDTO.getCertNo(), requestDTO.getBankCardNo(), requestDTO.getBankCode().getCode(), requestDTO.getBankCardMobileNo());
        boolean isSuccess = openAccountTemplate.doHandleSuccessOrder(
                record,
                requestDTO.getGroupAccountNo(),
                () -> openAccountOrderService.updateOrder(AccountEntityBuilder.buildUpdateOpenAccountOrder(true, order, requestDTO)),
                true,
                accountBase,
                () -> accountPersonService.save(person),
                s2

        );
        return isSuccess ? OpenAccountOrderStatusEnum.SUCCESS : OpenAccountOrderStatusEnum.of(order.getStatus());
    }

    private OpenAccountOrderStatusEnum updateFailOrder(OpenAccountRecord record, OpenAccountOrder order, UpdateRegisterOrderRequestDTO requestDTO) {
        boolean isSuccess = openAccountTemplate.doHandleUnSuccessOrder(
                record,
                OpenAccountRecordStatusEnum.FAILURE,
                () -> openAccountOrderService.updateOrder(AccountEntityBuilder.buildUpdateOpenAccountOrder(false, order, requestDTO)),
                requestDTO.getErrorCode(),
                requestDTO.getErrorMessage()
        );
        return isSuccess ? OpenAccountOrderStatusEnum.FAILURE : OpenAccountOrderStatusEnum.of(order.getStatus());
    }

}
